package gscrapper.service;

import gscrapper.entity.SonyGameInfo;

import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.jsoup.Connection.Method;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;

public class SonyService {
    private static final String LOGIN_URL = "https://account.sonyentertainmentnetwork.com/j_spring_security_check";
    private static final String LIST_URL = "https://account.sonyentertainmentnetwork.com/cam/media/media-list!paginate.action?page=%d&filter=games";

    static {
        // http://stackoverflow.com/questions/7744075/how-to-connect-via-https-using-jsoup
        // keytool -import -v -file /path/to/file.crt -keystore /path/to/file.jks -storepass guessit
        System.setProperty("javax.net.ssl.trustStore", "account.sonyentertainmentnetwork.com.jks");
    }

    private String locateListTableEntry() {
        return "table#mediaListTable tbody tr";
    }

    private String locateGameInfo(int row, int column, String tag) {
        return String.format("%s:eq(%d) td:eq(%d) %s", locateListTableEntry(), row, column, tag);
    }

    private String locateTitle(int row) {
        return locateGameInfo(row, 1, "h4");
    }

    private String locateDescription(int row) {
        return locateGameInfo(row, 1, "p");
    }

    private String locatePublisher(int row) {
        return locateGameInfo(row, 1, "div");
    }

    private String getElementText(Document doc, String cssQuery) {
        Elements list = doc.select(cssQuery);
        return (list.isEmpty() ? "" : list.get(0).text());
    }

    private String getListURL(int page) {
        return String.format(LIST_URL, page);
    }

    private String locatePageControl() {
        return "span.pcontrol";
    }

    private String locatePurchased(int row) {
        return locateGameInfo(row, 3, "label#purchaseDate");
    }

    private String locateExpirationDate(int row) {
        return locateGameInfo(row, 4, "");
    }

    private int getTotalPages(Map<String, String> cookies) {
        try {
            String[] control = getElementText(Jsoup.connect(getListURL(1)).cookies(cookies).get(), locatePageControl())
                    .split(" of ");
            return (control.length > 1 ? Integer.parseInt(control[1]) : 0);
        } catch (Exception e) {
            return 0;
        }

    }

    private Map<String, String> signIn(String username, String password) {
        System.out.println("Signing in...");
        try {
            return Jsoup.connect(LOGIN_URL) //
                    .data("j_username", username) //
                    .data("j_password", password) //
                    .method(Method.POST) //
                    .execute() //
                    .cookies();
        } catch (IOException e) {
            return null;
        }
    }

    public List<SonyGameInfo> scrapp(String username, String password) {
        List<SonyGameInfo> list = new ArrayList<SonyGameInfo>();

        Map<String, String> cookies = signIn(username, password);

        int totalPages = getTotalPages(cookies);

        try {
            DateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");

            for (int page = 1; page <= totalPages; page++) {
                System.out.println(String.format("Scrapping page %d of %s", page, totalPages));
                Document doc = Jsoup.connect(getListURL(page)) //
                        .cookies(cookies) //
                        .get();

                for (int row = 0; row < doc.select(locateListTableEntry()).size(); row++) {
                    SonyGameInfo game = new SonyGameInfo();

                    game.setTitle(getElementText(doc, locateTitle(row)));
                    game.setDescription(getElementText(doc, locateDescription(row)));
                    game.setPublisher(getElementText(doc, locatePublisher(row)));
                    game.setPurchased(dateFormat.parse(getElementText(doc, locatePurchased(row))));

                    String expiration = getElementText(doc, locateExpirationDate(row));
                    game.setExpiration(expiration.equals("--") ? null : dateFormat.parse(expiration));

                    list.add(game);
                }
            }
        } catch (IOException e) {
        } catch (ParseException e) {
        }

        return list;
    }
}
